(module data-structures (lib "eopl.ss" "eopl")

  (require "lang.scm")                  ; for expression?
  (require "store.scm")                 ;; for  explicit refs 

  (provide (all-defined))               ; too many things to list

;;;;;;;;;;;;;;;; expressed values ;;;;;;;;;;;;;;;;

;;; an expressed value is either a number, a boolean or a procval.

  (define-datatype expval expval?
    (num-val
     (value number?))
    (bool-val
     (boolean boolean?))
    (proc-val 
     (proc proc?))
    (ref-val
     (ref reference?)))

;;; extractors:

  (define expval->num
    (lambda (v)
      (cases expval v
	(num-val (num) num)
	(else (expval-extractor-error 'num v)))))

  (define expval->bool
    (lambda (v)
      (cases expval v
	(bool-val (bool) bool)
	(else (expval-extractor-error 'bool v)))))

  (define expval->proc
    (lambda (v)
      (cases expval v
	(proc-val (proc) proc)
	(else (expval-extractor-error 'proc v)))))
  (define expval->ref
    (lambda (v)
      (cases expval v
	(ref-val (ref) ref)
	(else (expval-extractor-error 'reference v)))))  

  (define expval-extractor-error
    (lambda (variant value)
      (eopl:error 'expval-extractors "Looking for a ~s, found ~s"
	variant value)))

;;;;;;;;;;;;;;;; continuations ;;;;;;;;;;;;;;;;


  (define-datatype continuation continuation?
    (end-cont
     (count number?))                     ; []
    (diff1-cont                      ; cont[(- [] (value-of e2 env))]
      (e2 expression?)
      (env environment?)
      (cont continuation?)
      (count number?))
    (diff2-cont                      ; cont[(- val1 [])]
      (val1 expval?)
      (cont continuation?)
      (count number?))
    (mult1-cont                      ; cont[(* [] (value-of e2 env))]
      (e2 expression?)
      (env environment?)
      (cont continuation?)
      (count number?))
    (mult2-cont                      ; cont[(* val1 [])]
      (val1 expval?)
      (cont continuation?)
      (count number?))
    (begin1-cont
      (es (list-of expression?))
       (env environment?)
       (cont continuation?)
       (count number?))
;    (begin2-cont
;      (val1 expval?)
;      (cont continuation?)
;      (count number?))
    (rator-cont            ; cont[(apply-proc [] (value-of rand env))]
      (rand expression?)
      (env environment?)
      (cont continuation?)
      (count number?))
    (rand-cont                          ; cont[(apply-proc val1 [])]
      (val1 expval?)
      (cont continuation?)
      (count number?))
    (zero1-cont
     (cont continuation?)
     (count number?))
    (let-exp-cont
     (var symbol?)
     (body expression?)
     (env environment?)
     (cont continuation?)
     (count number?))
    (if-test-cont
     (exp1 expression?)
     (exp2 expression?)
     (env environment?)
     (cont continuation?)
     (count number?))
    
    (ref-cont
     (cont continuation?)
     (count number?))
    (deref-cont 
     (cont continuation?)
     (count number?))
    
    (setref1-cont                     
      (e2 expression?)
      (env environment?)
      (cont continuation?)
      (count number?))
    (setref2-cont                    
      (val1 expval?)
      (cont continuation?)
      (count number?))
    
    
    
    )


;;;;;;;;;;;;;;;; procedures ;;;;;;;;;;;;;;;;


  (define-datatype proc proc?
    (procedure
      (bvar symbol?)
      (body expression?)
      (env environment?)))

;;;;;;;;;;;;;;;; environment structures ;;;;;;;;;;;;;;;;

;; example of a data type built without define-datatype

  (define empty-env-record
    (lambda () 
      '()))

  (define extended-env-record
    (lambda (sym val old-env)
      (cons (list sym val) old-env)))
  
  (define empty-env-record? null?)
  
  (define environment?
    (lambda (x)
      (or (empty-env-record? x)
          (and (pair? x)
               (symbol? (car (car x)))
               (expval? (cadr (car x)))
               (environment? (cdr x))))))

  (define extended-env-record->sym
    (lambda (r)
      (car (car r))))

  (define extended-env-record->val
    (lambda (r)
      (cadr (car r))))

  (define extended-env-record->old-env
    (lambda (r)
      (cdr r)))

)